package com.wind.common.utils;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;

/**
 * 链路上下文
 * 该类用于在链路中管理日志、请求时间和异常信息
 * 提供了设置和获取这些信息的方法以及清除操作
 *
 * @author FengYin
 */
@Slf4j
public class TraceLogContext {
    // MDC中traceId的键
    private static final String TRACE_ID = "traceId";

    // 用于在线程间传递请求开始时间
    private final static InheritableThreadLocal<Long> REQUEST_TIME = new InheritableThreadLocal<>();

    // 用于在线程间传递异常信息
    private final static InheritableThreadLocal<Throwable> EXCEPTION = new InheritableThreadLocal<>();

    /**
     * 设置traceId
     * 如果traceId为空，则生成一个新的traceId
     *
     * @param traceId 可能为空的traceId
     */
    public static void setTraceId(String traceId) {
        if (StrUtil.isBlank(traceId)) {
            traceId = IdUtil.simpleUUID();
        }
        MDC.put(TRACE_ID, traceId);
    }

    /**
     * 设置traceId
     * 自动生成一个新的traceId并设置
     */
    public static void setTraceId() {
        setTraceId(null);
    }

    /**
     * 获取当前的traceId
     * 如果MDC中没有traceId，则返回空字符串
     *
     * @return 当前的traceId或空字符串
     */
    public static String getTraceId() {
        String traceId = MDC.get(TRACE_ID);
        if (traceId == null) {
            traceId = "";
        }
        return traceId;
    }

    /**
     * 移除当前的traceId
     */
    public static void removeTraceId() {
        MDC.remove(TRACE_ID);
    }

    /**
     * 设置请求开始时间
     */
    public static void setRequestTime() {
        REQUEST_TIME.set(System.currentTimeMillis());
    }

    /**
     * 获取请求开始时间
     * 如果没有设置请求开始时间，则返回-1
     *
     * @return 请求开始时间或-1
     */
    public static long getRequestTime() {
        Long result = REQUEST_TIME.get();
        if (result == null) {
            return -1L;
        }
        return result;
    }

    /**
     * 移除请求开始时间
     */
    public static void removeRequestTime() {
        REQUEST_TIME.remove();
    }

    /**
     * 设置异常信息
     *
     * @param e 异常实例
     */
    public static void setException(Throwable e) {
        EXCEPTION.set(e);
    }

    /**
     * 获取当前的异常信息
     *
     * @return 当前的异常实例
     */
    public static Throwable getException() {
        return EXCEPTION.get();
    }

    /**
     * 移除当前的异常信息
     */
    public static void removeException() {
        EXCEPTION.remove();
    }

    /**
     * 清空链路上下文中的所有信息
     * 包括traceId、请求开始时间和异常信息
     */
    public static void clear() {
        removeTraceId();
        removeRequestTime();
        removeException();
    }
}
